package com.lechi.web.server.handle;

import com.alibaba.fastjson2.JSON;
import com.lechi.iot.netty.channel.ITcpChannel;
import com.lechi.iot.netty.utils.NettyCacheUtils;
import com.lechi.web.common.utils.DateUtils;
import com.lechi.web.common.utils.bean.BeanUtils;
import com.lechi.web.constants.Constants;
import com.lechi.web.framework.util.GuavaCacheUtil;
import com.lechi.web.framework.websocket.WebSocketServer;
import com.lechi.web.framework.websocket.WebSocketUtil;
import com.lechi.web.job.BatchInsertJob;
import com.lechi.web.system.domain.IotMonitorDataBo;
import com.lechi.web.system.domain.IotWeatherDeviceBo;
import com.lechi.web.system.domain.IotWeatherSensorParseBo;
import com.lechi.web.util.AlarmRulesUtil;
import com.lechi.web.util.RecordFileUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.Charset;
import java.util.*;

/**
 * 二代站报文接收
 */
@Slf4j
@Sharable
public class DictInboundMessageHandler extends SimpleChannelInboundHandler<ByteBuf> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) {
        String hostName = ctx.channel().remoteAddress().toString();
        ITcpChannel tcpChannel = NettyCacheUtils.get(hostName, ITcpChannel.class);
        try {
            String dataRecord = byteBuf.toString(Charset.defaultCharset()).trim();
            log.error("通过设备地址： {} ，收到报文字符串：{}, 可读字节码长度：{}，字符长度：{}", hostName, dataRecord, byteBuf.readableBytes(), dataRecord.length());
            if (tcpChannel == null) {
                log.error("通过设备地址{}获取管道失败或管道未注册设备，报文：{} 不解析！", hostName, dataRecord);
                return;
            }
            final String[] dataArr = dataRecord.split(",");
            final String checkNumSource = dataArr[dataArr.length - 2];
            final int checkNumTarget = dataRecord.substring(0, dataRecord.length() - 7).chars().sum() % 10000;
            if (Integer.parseInt(checkNumSource) != checkNumTarget) {
                final Long deviceId = GuavaCacheUtil.getBiDeviceIdAndIPMap().inverse().get(hostName);
                Map<String, Object> deviceDataMap = new HashMap<>();
                deviceDataMap.put("record", dataRecord);
                deviceDataMap.put("time", DateUtils.getTime());
                WebSocketServer.sendInfo(deviceId, JSON.toJSONString(deviceDataMap));
                log.error("校验失败格式不正确，报文忽略：{}, 报文原始校验码：{}, 计算获取校验码{}", dataRecord, checkNumSource, checkNumTarget);
                return;
            }
            final List<IotWeatherDeviceBo> weatherDeviceBoList = (List<IotWeatherDeviceBo>) GuavaCacheUtil.getCmdParseTableMap().get(Constants.WEATHER2017);
            if (weatherDeviceBoList == null || weatherDeviceBoList.isEmpty()) {
                log.error("WEATHER-2017网关没有获取到解析规则，该报文:{}不解析!", dataRecord);
                return;
            }
            String sensorFlag = "";
            int watchDataBeginIndex = 0;
            int watchDataEndIndex = 0;
//            int stateNum = 0;
//            int qualityCodeIndex = 0;  // 质量码位置索引
            for (IotWeatherDeviceBo iotWeatherDeviceBo : weatherDeviceBoList) {
                boolean deviceSignBool = Objects.equals(iotWeatherDeviceBo.getDeviceSign(), dataArr[iotWeatherDeviceBo.getDeviceSignIndex()]);
                boolean instrumentIdBool = Objects.equals(iotWeatherDeviceBo.getInstrumentId(), dataArr[iotWeatherDeviceBo.getInstrumentIndex()]);
                boolean stationNumBool = Objects.equals(iotWeatherDeviceBo.getDeviceStation(), dataArr[iotWeatherDeviceBo.getStationNumIndex()]);
                boolean serviceTypeBool = Objects.equals(iotWeatherDeviceBo.getServiceType(), dataArr[iotWeatherDeviceBo.getServiceTypeIndex()]);
                if (deviceSignBool && instrumentIdBool && stationNumBool && serviceTypeBool) {
                    sensorFlag = String.join("_", String.valueOf(iotWeatherDeviceBo.getDeviceId()), iotWeatherDeviceBo.getInstrumentId(), iotWeatherDeviceBo.getDeviceStation());
                    GuavaCacheUtil.getDeviceLastDated().put(String.valueOf(iotWeatherDeviceBo.getDeviceId()), new Date());
                    GuavaCacheUtil.getBiDeviceIdAndIPMap().forcePut(iotWeatherDeviceBo.getDeviceId(), hostName);
                    watchDataBeginIndex = iotWeatherDeviceBo.getWatchDataIndex();
                    watchDataEndIndex = watchDataBeginIndex + Integer.parseInt(dataArr[iotWeatherDeviceBo.getSensorNumIndex()]) * 2;
//                    qualityCodeIndex =iotWeatherDeviceBo.getQualityIndex(); // 质量码备用
//                    stateNum = Integer.parseInt(dataArr[iotWeatherDeviceBo.getStateNumIndex()]);
                    break;
                }
            }
            final String[] sensorData = ArrayUtils.subarray(dataArr, watchDataBeginIndex, watchDataEndIndex);
            final String[] stateData = ArrayUtils.subarray(dataArr, watchDataEndIndex + 1, dataArr.length - 2);
            final List<IotWeatherSensorParseBo> weatherParseDtoList = (List<IotWeatherSensorParseBo>) GuavaCacheUtil.getCmdParseTableMap().get(sensorFlag);
            if (StringUtils.isBlank(sensorFlag) || watchDataEndIndex == 0 || sensorData.length == 0) {
                log.error("WEATHER-2017网关设备:{}没有获取到解析规则，该报文不解析!", sensorFlag);
                return;
            }
            String[] sensorAndStateData = new String[sensorData.length + stateData.length];
            System.arraycopy(sensorData, 0, sensorAndStateData, 0, sensorData.length);
            System.arraycopy(stateData, 0, sensorAndStateData, sensorData.length, stateData.length);
            List<IotMonitorDataBo> weather2017DeviceDataList = new ArrayList<>();
            for (int i = 0; i < sensorAndStateData.length; i = i + 2) {
                String sensorSign = sensorAndStateData[i].trim();
//                log.error("sensorData================sensorSign:{}!", sensorSign);
                for (IotWeatherSensorParseBo sensorParseBo : weatherParseDtoList) {
                    if (Objects.equals(sensorSign, sensorParseBo.getSensorSign())) {
//                        log.error("sensorParseBo.getSensorSign():{}!", sensorParseBo.getSensorSign());
                        IotMonitorDataBo iotMonitorPageData = new IotMonitorDataBo();
                        BeanUtils.copyProperties(sensorParseBo, iotMonitorPageData);
                        iotMonitorPageData.setReceiveData(dataRecord);
                        float v = Integer.parseInt(sensorAndStateData[i + 1]); // 保留1位小数点
                        long digit = Objects.isNull(sensorParseBo.getSensorDigit()) ? 1L : sensorParseBo.getSensorDigit();
                        v = Math.round(v * Math.pow(10, digit) + 0.005f) / (float) Math.pow(10, digit);
                        iotMonitorPageData.setDoubleValue(v);
                        iotMonitorPageData.setDateTime(new Date());
                        iotMonitorPageData.setBaseTime(DateUtils.getBaseTime());
                        iotMonitorPageData.setTableName("iot_monitor_data_" + sensorParseBo.getDeviceId());
                        try {
                            BatchInsertJob.workQueue.put(iotMonitorPageData);
                            weather2017DeviceDataList.add(iotMonitorPageData);
                        } catch (InterruptedException e) {
                            log.error("workQueue put InterruptedException!", e);
                        }
                        AlarmRulesUtil.alarmRuleChain(iotMonitorPageData);
                        WebSocketUtil.sendToMonitorPage(iotMonitorPageData);
                        GuavaCacheUtil.getMonitorDataMap().put(iotMonitorPageData.getDeviceId(), iotMonitorPageData.getSensorAliasId(), iotMonitorPageData);
                    }
                }
            }
            WebSocketUtil.sendToDevicePage(Constants.WEATHER2017, weather2017DeviceDataList);
            RecordFileUtil.producerRecord(Constants.WEATHER2017, weather2017DeviceDataList);
        } catch (Exception e) {
            log.error("WEATHER-2017网关解析异常!", e);
        }
    }
}
